﻿using DevExpress.Blazor;
using DevExpress.ExpressApp.Blazor.Components;
using DevExpress.ExpressApp.Blazor.Components.Models;
using DevExpress.ExpressApp.Blazor.Editors.Models;
using EasyXaf.DynamicForm.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using System.Data;
using System.Dynamic;

namespace EasyXaf.DynamicForm.Blazor.Components;

public class TableComponent : FieldComponent
{
    protected override ComponentModelBase CreateComponentModel()
    {
        var table = (Table)Field;

        if (Data.TryGetValue(table.Name, out var value))
        {
            if (value is List<ExpandoObject> expandoObjects)
            {
                Data[table.Name] = expandoObjects;
            }
            else if (value is List<object> objects)
            {
                Data[table.Name] = objects.OfType<ExpandoObject>().ToList();
            }
            else
            {
                Data[table.Name] = new List<ExpandoObject>();
            }
        }
        else
        {
            Data[table.Name] = new List<ExpandoObject>();
        }

        var data = (List<ExpandoObject>)Data[table.Name];
        var dataTable = new DataTable();

        if (data.Count == 0)
        {
            foreach (var column in table.Columns)
            {
                dataTable.Columns.Add(column.Name);
            }
        }

        var model = new DxGridModel
        {
            Data = data.Count > 0 ? data : dataTable,
            ShowAllRows = true,
            ValidationEnabled = false,
        };

        if (!table.IsCurrentlyReadOnly)
        {
            model.EditMode = GridEditMode.EditCell;
            model.EditNewRowPosition = GridEditNewRowPosition.LastRow;
            model.EditModelSaving = EventCallback.Factory.Create<GridEditModelSavingEventArgs>(this, async args =>
            {
                if (args.EditModel is ExpandoObject editModel)
                {
                    if (args.IsNew)
                    {
                        data.Add(editModel);
                    }
                    else if (args.DataItem is ExpandoObject dataItem)
                    {
                        data[data.IndexOf(dataItem)] = editModel;
                    }
                    await ValueChanged.InvokeAsync();
                }
            });
            model.CustomizeEditModel = EventCallback.Factory.Create<GridCustomizeEditModelEventArgs>(this, args =>
            {
                if (args.IsNew)
                {
                    var item = new ExpandoObject();
                    foreach (var column in table.Columns)
                    {
                        item.TryAdd(column.Name, null);
                    }
                    args.EditModel = item;
                }
            });
        }

        var columnModels = new List<ComponentModelBase>();

        foreach (var column in table.Columns)
        {
            var columnModel = new DxGridDataColumnModel
            {
                FieldName = column.Name,
                Caption = column.Caption,
                ReadOnly = column.IsCalculated || column.IsCurrentlyReadOnly,
                Visible = column.ActualVisible
            };

            if (columnModel.ReadOnly)
            {
                columnModel.DataRowEditorVisible = false;
            }
            else
            {
                columnModel.CellEditTemplate = context => builder =>
                {
                    var editModel = context.EditModel as IDictionary<string, object>;
                    var valueType = column.ValueType?.Trim()?.ToLowerInvariant();

                    Type componentType = null;

                    if (string.IsNullOrWhiteSpace(valueType) || valueType == "string")
                    {
                        componentType = typeof(TextBoxComponent);
                    }
                    else if (valueType == "int" || valueType == "long")
                    {
                        componentType = typeof(NumberComponent<int>);
                    }
                    else if (valueType == "float" || valueType == "double" || valueType == "number")
                    {
                        componentType = typeof(NumberComponent<double>);
                    }
                    else if (valueType == "bool")
                    {
                        componentType = typeof(CheckBoxComponent);
                    }

                    if (componentType != null)
                    {
                        builder.OpenComponent(0, componentType);
                        builder.AddAttribute(1, nameof(Field), column);
                        builder.AddAttribute(2, nameof(Inline), true);
                        builder.AddAttribute(3, nameof(Data), editModel);
                        builder.CloseComponent();
                    }
                };
            }

            columnModels.Add(columnModel);
        }

        if (!table.IsCurrentlyReadOnly)
        {
            columnModels.Add(new DxGridCommandColumnModel
            {
                CellDisplayTemplate = context =>
                {
                    var model = new DxButtonModel
                    {
                        Text = "删除",
                        RenderStyle = ButtonRenderStyle.Link,
                        Click = EventCallback.Factory.Create<MouseEventArgs>(this, async args =>
                        {
                            if (context.DataItem is ExpandoObject dataItem)
                            {
                                data.Remove(dataItem);
                                await ValueChanged.InvokeAsync();
                            }
                        })
                    };
                    return ComponentModelObserver.Create(model, model.GetComponentContent());
                },
                CellEditTemplate = context =>
                {
                    var model = new DxButtonModel
                    {
                        Text = "删除",
                        Enabled = false,
                        RenderStyle = ButtonRenderStyle.Link,
                    };
                    return ComponentModelObserver.Create(model, model.GetComponentContent());
                }
            });
        }

        model.Columns = builder =>
        {
            var sequence = 0;
            foreach (var columnModel in columnModels)
            {
                builder.AddContent(sequence++, ComponentModelObserver.Create(columnModel, columnModel.GetComponentContent()));
            }
        };

        return model;
    }
}
